# update log
# 2020.10.20
# hiroshi:
#   add a option: keepNoPromis
#   add a Exception: DbNoDataError
#tam:
#   fix a bug: (out, err) = p.communicate. The out and err can't work correctly
 
# 2020.09.25  Tam :
# 1. user argparse, now can set pyPATH by command line argument
# 2. remove useless code
# 3. add debug option for convenient to debug
# 4. 'print(msg)', print clause in DS2res.py and FT2res.py now can correctly show on screen.
# 5. replace some 'str' with 'repr', now can correctly print out'KeyError'

import os, sys, re
import subprocess
import traceback
import argparse
import pathlib
from TOOLS import *

## PRG_FIL stores values generated by DS2res.py or FT2res.py. It has 3 lines.
# a example:
#line1:   FRGBC089
#line2:   /data/yms/SM/WSSM8057/MOSFET_HIST/FT/FETTEST_LVM/STAGE/NotProcessed/manual/20201013_work_on_latest_code/tang//tests/FT/V50396-T1-GE3-V_N51D935.5_FT_20200325005457.res
#line3:   /data/yms/SM/WSSM8057/MOSFET_HIST/FT/FETTEST_LVM/STAGE/NotProcessed/manual/20201013_work_on_latest_code/tang//ref/CSVFinalTestsFileCombinedForDatalog20200522.csv.old
#line1 is PROGRAM name parsed from datafile
#line2 is res file name(limit value hasn't been added). After adding limit value, V50396-T1-GE3-V_N51D935.5_FT_20200325005457.res will be moved to -OutDir
#Because the timestamp 2020032500545 maybe varies according to script runtime.
#line3 is now useless because bin mapping filename is now passed from argument.

# DEBUG and pyPATH can be set in script or passed from argument. 
# check both values in script and argument. Find which value is diff from default value, then set variable to this one. Argument comes firstly. Default = 0, '/bin/python3'
DEBUG = 0
pyPATH = '/bin/python3'
BIN_MAP = ''    #bin map file
PROGRAM = ''    #PROGRAM name get from PRG_FIL
PRG_FIL = ''    
RES_FIL = ''    #res filename(line2)
LIM_FIL = ''    #limit filename = PROGRAM + '.tes'
##
class DbNoDataError(Exception):
    pass

def main():
    global DEBUG
    global pyPATH
    global BIN_MAP
    global PROGRAM
    global PRG_FIL
    global RES_FIL
    global LIM_FIL
    parser = argparse.ArgumentParser(description = 'option example')
    parser.add_argument('DAT_FIL', help='name of datafile', metavar = 'datafile')
    parser.add_argument('-debug', help='keep temp file, and print more info', action='count', default = 0)
    parser.add_argument('-KeepNoPromis', help='keep the no result into current loader folder, default:0 , not keep', action='count', default = 0, dest='keepNoPromis')
    parser.add_argument('-v', '--version', help='print version', action='version', version='%(prog)s 2.0')
    parser.add_argument('-py', help='set python path, default /bin/python3', default = '/bin/python3', metavar = '= Path')
    parser.add_argument('-db', help='database from where getting info to tell HVM or LVM, default REFDB_PROD', default='REFDB_PROD', metavar = '= Database')
    parser.add_argument('-limDir', help='directory of where to find limit file', metavar = '= Dir')
    parser.add_argument('-type', help='DS or FT file? Choice = [DS, FT], default None, judged by folder name', choices=['DS', 'FT'], metavar = '= Choice')
    parser.add_argument('-DS_HVM_BIN_MAP', help='filename of DS HVM bin mapping, default "HVM_Sort_Bin_Mapping.csv"', 
                        default="HVM_Sort_Bin_Mapping.csv", metavar = '= File')
    parser.add_argument('-DS_LVM_BIN_MAP', help='filename of DS LVM bin mapping, default "Vishay_Test_Binning_Mapping.csv"', 
                        metavar = '= File', default="Vishay_Test_Binning_Mapping.csv")
    parser.add_argument('-FT_BIN_MAP', help='filename of FT bin mapping, default "CSVFinalTestsFileCombinedForDatalog20200522.csv"',
                        metavar = '= File', default="CSVFinalTestsFileCombinedForDatalog20200522.csv")
    parser.add_argument('-outDir', help='output file directory', required=True, metavar = '= Dir')
    args = parser.parse_args()
     
    ##DEBUG and pyPATH can be set in script or passed from argument. Argument comes firstly
    if not DEBUG:
        DEBUG = args.debug

    assert pyPATH == '/bin/python3' or args.py == '/bin/python3', 'confict python path, check pyPATH and command line argument py'
    pyPATH = args.py if args.py != '/bin/python3' else pyPATH
    ##
    ##########################################################################################
    ## parse dat file 
    directorys = args.DAT_FIL.split('/')  # for linux
    directorys = directorys[0:-1]
    src_dir = pathlib.Path(__file__).parent.absolute()
    ##
    ## A konwn issue: 
    #       When content of stdout in DS2res.py or FT2res.py is too large, the pipe will be blocked.
    #       This is subprocess issue.
    #  Solution: use you own file pipe.
    if args.type == 'DS' or ((not args.type) and ('DS' in directorys) and ('FT' not in directorys)):
        command = [f"{pyPATH}", fr"{src_dir}/DS2res.py", fr"{args.DAT_FIL}", "-debug", fr"{DEBUG}", '-db', fr"{args.db}", 
                  '-DS_HVM_BIN_MAP', f'{args.DS_HVM_BIN_MAP}', '-DS_LVM_BIN_MAP', f'{args.DS_LVM_BIN_MAP}']
        p = subprocess.Popen(command, stdout= subprocess.PIPE, stderr=subprocess.PIPE)
    elif args.type == 'FT' or ((not args.type) and ('DS' not in directorys) and ('FT' in directorys)):
        command = [f"{pyPATH}", fr"{src_dir}/FT2res.py", f"{args.DAT_FIL}", '-debug', f"{DEBUG}", '-FT_BIN_MAP', f"{args.FT_BIN_MAP}"]
        p = subprocess.Popen(command,stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    else:
        raise Exception('incorrect datafile path, path should include DS or FT fold, or set option "type"')
    
    p.wait()
    (out, err) = p.communicate()
    if DEBUG and out:
         print(out.decode('utf-8'))
    if p.returncode == 10:
        if args.keepNoPromis != 0:
            raise DbNoDataError(f"{p.returncode},{str(err.decode('utf8'))}")
        else:
            p.returncode = 1
            raise BaseException(f"{p.returncode},{str(err.decode('utf8'))}")
    elif p.returncode != 0:
        raise Exception(f"{p.returncode},{str(err.decode('utf8'))}")
    ##
    #add limit file
    #if not args.limDir:
    #    sys.exit(0)

    # read PRG_FIL, .prg
    PRG_FIL = args.DAT_FIL + '.prg'
    with open(PRG_FIL, 'r') as F:
        PROGRAM = F.readline().strip()
        RES_FIL = F.readline().strip()
        BIN_MAP = F.readline().strip()
    # search limit file, add limit value to .res file
    for file in os.listdir(args.limDir):
        FindFile = re.search(rf'^{PROGRAM}\.tes(\.gz)?$', file, flags=re.I)
        if FindFile:
            LIM_FIL = file
            break
    if FindFile:
        LIM_FIL = os.path.join(args.limDir, LIM_FIL)
    else:
        raise Exception(f"can not find limit file {args.limDir}/{PROGRAM}.tes(.gz), for script dat2resAddLim.py")
    ## Add limit value to res file. In-file and Out-file are both res file and keep filename unchanged.
    command = [f"{args.py}", fr"{src_dir}/add_tes_limit.py", f"{RES_FIL}", f"{LIM_FIL}", f"{BIN_MAP}", f"{args.outDir}", '-debug', f"{DEBUG}"]
    p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p.wait()
    (out, err) = p.communicate()
    if DEBUG and out:
        print(out.decode('utf-8'))
    if p.returncode != 0:
        raise Exception(f"{str(err.decode('utf8'))}")
    ##
if __name__ == '__main__':
    try:
        main()
    except SystemExit as e:
        if str(e) == '0':
            pass
    except DbNoDataError as ins:
        if not DEBUG:
            rm_file(RES_FIL)
        exit_for_loader(10, repr(ins))
    except BaseException as ins:
        #print("BaseException caught! {}".format(repr(ins)))
        if not DEBUG:
            rm_file(RES_FIL)
        else:
            print(traceback.format_exc())
        exit_for_loader(1, repr(ins))
    finally:
        if not DEBUG:
            rm_file(PRG_FIL)
